I've implemented gravity in what probably a non-standard way, but the calculus involved in actual rigid-body physics is too much math for me at my current ability.
CBall is my Ball class containing x and y positions, and x and y velocities. I have a vector of CBall pointers. I process them in this function named 'Gravity' detailed below.
I was curious to any comment at all on how to improve my design, or a new direction. This function runs once per frame, and processes every CBall pointed to in vpCBall (vector of pointers to CBall).
Code:
void Gravity(vector<CBall*> &vpCBall, int Gravity_Setting, sf::String &Text)
{
// Is gravity on?
if (Gravity_Setting == WEIGHTLESS) return;
// Iterate through the CBall list
// Reset Active Balls counter each loop
int ActiveBalls = 0;
for (vector<CBall*>::iterator iter = vpCBall.begin(); iter != vpCBall.end(); ++iter)
{
if((*iter)->AtRest) continue;
++ActiveBalls;
// Spreed: Copy the Class members to local variables
float x_pos = (*iter)->x_pos;
float x_vel = (*iter)->x_vel;
float y_pos = (*iter)->y_pos;
float y_vel = (*iter)->y_vel;
y_vel += GRAVITY; //0.82
y_pos += y_vel;
x_vel *= DRAG; // 0.995
x_pos += x_vel;
// If Collided with Floor...
if (y_pos > SCREEN_BOTTOM)
{
// Reverse momentum - albeit weaker (80-95% strength)
y_vel *= -INERTIA; // 0.95
// Is Kinetic energy exhausted?
// Note: Cutoff must be less than GRAVITY
// Reason: This section takes care of the problem of the "vibrating" balls.
// No point to vibrating balls, so after a CUTOFF in movement in
// the x and y axis, simply zero out both and mark it AtRest=true
assert(CUTOFF < GRAVITY);
if (fabs(y_vel) < CUTOFF && fabs(x_vel) < CUTOFF)
{
//cout << "Resting Ball..." << endl;
x_vel = 0;
y_vel = 0;
(*iter)->AtRest = true;
}
// Set Ball to just above floorline
// Reason: This garuntees the ball will not be caught next time
// through the loop and re-considered for -another- immediate
// velocity inversion
y_pos = SCREEN_BOTTOM - 0.001;
}
// Check Screen Bounds
// Reason: If the balls roll off the screen to 105% of the screen
// width, simply stop considering them for physics calculations.
if (x_pos > (SCREEN_RIGHT * 1.05))
{
x_vel = 0;
y_vel = 0;
(*iter)->AtRest = true;
}
// Put the locals back into the Class
(*iter)->x_pos = x_pos;
(*iter)->x_vel = x_vel;
(*iter)->y_pos = y_pos;
(*iter)->y_vel = y_vel;
}
// String stream used for screen message
stringstream ss("");
ss << "Active Balls: " << ActiveBalls << " / " << vpCBall.size();
Text.SetText(ss.str());
}
There are some kludges, like artificially adjusting the y position after a velocity inversion (the part where I multiply y_vel by a negative INERTIA) so that the y_vel isn't flipped again on the following loop/frame.